"""
Flask API测试工具 - 提供API测试和性能监控功能
包含API测试、性能基准测试、负载测试等功能
"""

from flask import Flask, request, jsonify, g
import os
import sys
import time
import asyncio
import threading
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional
from concurrent.futures import ThreadPoolExecutor, as_completed
import statistics
import json

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python_backend_toolkit.http_client import HTTPClient, AsyncHTTPClient
from python_backend_toolkit.logging import get_logger, setup_logging
from python_backend_toolkit.utils import (
    generate_uuid, format_datetime, calculate_execution_time
)
from python_backend_toolkit.api.responses import (
    SuccessResponse, ErrorResponse, CreatedResponse
)
from python_backend_toolkit.api.exceptions import ValidationError


class APITester:
    """API测试器"""
    
    def __init__(self):
        self.http_client = HTTPClient()
        self.async_http_client = AsyncHTTPClient()
        self.logger = get_logger("APITester")
        self.test_results = []
    
    def test_endpoint(self, method: str, url: str, headers: Dict = None, 
                     data: Any = None, expected_status: int = 200) -> Dict[str, Any]:
        """测试单个API端点"""
        start_time = time.time()
        test_id = generate_uuid()
        
        try:
            # 发送请求
            if method.upper() == 'GET':
                response = self.http_client.get(url, headers=headers)
            elif method.upper() == 'POST':
                response = self.http_client.post(url, json=data, headers=headers)
            elif method.upper() == 'PUT':
                response = self.http_client.put(url, json=data, headers=headers)
            elif method.upper() == 'DELETE':
                response = self.http_client.delete(url, headers=headers)
            else:
                raise ValueError(f"Unsupported method: {method}")
            
            duration = time.time() - start_time
            
            # 分析响应
            result = {
                "test_id": test_id,
                "method": method.upper(),
                "url": url,
                "status_code": response.status_code,
                "expected_status": expected_status,
                "success": response.status_code == expected_status,
                "duration": duration,
                "response_size": len(response.content) if response.content else 0,
                "timestamp": datetime.utcnow().isoformat()
            }
            
            # 尝试解析JSON响应
            try:
                result["response_data"] = response.json()
            except:
                result["response_text"] = response.text[:500]  # 限制长度
            
            self.test_results.append(result)
            
            self.logger.info(
                "API test completed",
                test_id=test_id,
                method=method,
                url=url,
                status_code=response.status_code,
                duration=duration,
                success=result["success"]
            )
            
            return result
            
        except Exception as e:
            duration = time.time() - start_time
            result = {
                "test_id": test_id,
                "method": method.upper(),
                "url": url,
                "status_code": None,
                "expected_status": expected_status,
                "success": False,
                "duration": duration,
                "error": str(e),
                "timestamp": datetime.utcnow().isoformat()
            }
            
            self.test_results.append(result)
            
            self.logger.error(
                "API test failed",
                test_id=test_id,
                method=method,
                url=url,
                error=str(e),
                duration=duration
            )
            
            return result
    
    def batch_test(self, test_cases: List[Dict[str, Any]]) -> Dict[str, Any]:
        """批量测试API"""
        start_time = time.time()
        batch_id = generate_uuid()
        results = []
        
        self.logger.info(
            "Batch test started",
            batch_id=batch_id,
            test_count=len(test_cases)
        )
        
        for i, test_case in enumerate(test_cases):
            self.logger.info(f"Running test {i+1}/{len(test_cases)}")
            
            result = self.test_endpoint(
                method=test_case.get('method', 'GET'),
                url=test_case.get('url'),
                headers=test_case.get('headers'),
                data=test_case.get('data'),
                expected_status=test_case.get('expected_status', 200)
            )
            
            results.append(result)
        
        total_duration = time.time() - start_time
        
        # 统计结果
        successful_tests = sum(1 for r in results if r['success'])
        failed_tests = len(results) - successful_tests
        avg_duration = statistics.mean([r['duration'] for r in results])
        
        batch_result = {
            "batch_id": batch_id,
            "total_tests": len(test_cases),
            "successful_tests": successful_tests,
            "failed_tests": failed_tests,
            "success_rate": successful_tests / len(test_cases) * 100,
            "total_duration": total_duration,
            "average_duration": avg_duration,
            "results": results,
            "timestamp": datetime.utcnow().isoformat()
        }
        
        self.logger.info(
            "Batch test completed",
            batch_id=batch_id,
            total_tests=len(test_cases),
            successful_tests=successful_tests,
            failed_tests=failed_tests,
            success_rate=batch_result["success_rate"],
            total_duration=total_duration
        )
        
        return batch_result
    
    def load_test(self, url: str, method: str = 'GET', concurrent_users: int = 10,
                  duration_seconds: int = 30, data: Any = None, headers: Dict = None) -> Dict[str, Any]:
        """负载测试"""
        start_time = time.time()
        load_test_id = generate_uuid()
        results = []
        
        self.logger.info(
            "Load test started",
            load_test_id=load_test_id,
            url=url,
            method=method,
            concurrent_users=concurrent_users,
            duration_seconds=duration_seconds
        )
        
        def make_request():
            """发送单个请求"""
            try:
                request_start = time.time()
                
                if method.upper() == 'GET':
                    response = self.http_client.get(url, headers=headers)
                elif method.upper() == 'POST':
                    response = self.http_client.post(url, json=data, headers=headers)
                else:
                    response = self.http_client.get(url, headers=headers)
                
                request_duration = time.time() - request_start
                
                return {
                    "status_code": response.status_code,
                    "duration": request_duration,
                    "success": 200 <= response.status_code < 400,
                    "timestamp": time.time()
                }
            except Exception as e:
                return {
                    "status_code": None,
                    "duration": time.time() - request_start,
                    "success": False,
                    "error": str(e),
                    "timestamp": time.time()
                }
        
        # 使用线程池进行并发测试
        with ThreadPoolExecutor(max_workers=concurrent_users) as executor:
            end_time = start_time + duration_seconds
            
            while time.time() < end_time:
                # 提交并发请求
                futures = []
                for _ in range(concurrent_users):
                    if time.time() >= end_time:
                        break
                    future = executor.submit(make_request)
                    futures.append(future)
                
                # 收集结果
                for future in as_completed(futures):
                    if time.time() >= end_time:
                        break
                    try:
                        result = future.result(timeout=10)
                        results.append(result)
                    except Exception as e:
                        results.append({
                            "status_code": None,
                            "duration": 0,
                            "success": False,
                            "error": str(e),
                            "timestamp": time.time()
                        })
        
        total_duration = time.time() - start_time
        
        # 统计结果
        if results:
            successful_requests = sum(1 for r in results if r['success'])
            failed_requests = len(results) - successful_requests
            durations = [r['duration'] for r in results if 'duration' in r]
            
            load_test_result = {
                "load_test_id": load_test_id,
                "url": url,
                "method": method.upper(),
                "concurrent_users": concurrent_users,
                "duration_seconds": duration_seconds,
                "total_requests": len(results),
                "successful_requests": successful_requests,
                "failed_requests": failed_requests,
                "success_rate": successful_requests / len(results) * 100,
                "requests_per_second": len(results) / total_duration,
                "average_response_time": statistics.mean(durations) if durations else 0,
                "min_response_time": min(durations) if durations else 0,
                "max_response_time": max(durations) if durations else 0,
                "median_response_time": statistics.median(durations) if durations else 0,
                "total_duration": total_duration,
                "timestamp": datetime.utcnow().isoformat()
            }
        else:
            load_test_result = {
                "load_test_id": load_test_id,
                "url": url,
                "method": method.upper(),
                "concurrent_users": concurrent_users,
                "duration_seconds": duration_seconds,
                "total_requests": 0,
                "successful_requests": 0,
                "failed_requests": 0,
                "success_rate": 0,
                "requests_per_second": 0,
                "error": "No requests completed",
                "total_duration": total_duration,
                "timestamp": datetime.utcnow().isoformat()
            }
        
        self.logger.info(
            "Load test completed",
            **{k: v for k, v in load_test_result.items() if k != 'timestamp'}
        )
        
        return load_test_result
    
    def get_test_history(self, limit: int = 100) -> List[Dict[str, Any]]:
        """获取测试历史"""
        return self.test_results[-limit:]
    
    def clear_test_history(self):
        """清空测试历史"""
        self.test_results.clear()
        self.logger.info("Test history cleared")


def create_api_testing_app() -> Flask:
    """创建API测试Flask应用"""
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'api-testing-secret'
    
    # 初始化日志
    setup_logging()
    logger = get_logger("APITestingApp")
    
    # 初始化API测试器
    api_tester = APITester()
    
    # ========================================================================
    # 中间件
    # ========================================================================
    
    @app.before_request
    def before_request():
        """请求前处理"""
        g.request_id = generate_uuid()
        g.start_time = time.time()
        
        logger.info(
            "Request started",
            request_id=g.request_id,
            method=request.method,
            path=request.path
        )
    
    @app.after_request
    def after_request(response):
        """请求后处理"""
        duration = time.time() - g.start_time
        
        logger.info(
            "Request completed",
            request_id=g.request_id,
            status_code=response.status_code,
            duration=duration
        )
        
        return response
    
    @app.errorhandler(ValidationError)
    def handle_validation_error(e):
        return jsonify(ErrorResponse.create(message=str(e)).dict()), 400
    
    @app.errorhandler(Exception)
    def handle_general_error(e):
        logger.error("Unhandled error", error=str(e))
        return jsonify(ErrorResponse.create(
            message="Internal server error"
        ).dict()), 500
    
    # ========================================================================
    # API测试端点
    # ========================================================================
    
    @app.route('/test/single', methods=['POST'])
    def test_single_endpoint():
        """测试单个API端点"""
        try:
            data = request.get_json()
            
            method = data.get('method', 'GET').upper()
            url = data.get('url')
            headers = data.get('headers', {})
            request_data = data.get('data')
            expected_status = data.get('expected_status', 200)
            
            if not url:
                raise ValidationError("URL is required")
            
            result = api_tester.test_endpoint(
                method=method,
                url=url,
                headers=headers,
                data=request_data,
                expected_status=expected_status
            )
            
            response = SuccessResponse.create(
                data={"test_result": result},
                message="API test completed"
            )
            return jsonify(response.dict())
            
        except ValidationError as e:
            raise
        except Exception as e:
            logger.error("Single test error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Test failed"
            ).dict()), 500
    
    @app.route('/test/batch', methods=['POST'])
    def test_batch_endpoints():
        """批量测试API端点"""
        try:
            data = request.get_json()
            test_cases = data.get('test_cases', [])
            
            if not test_cases:
                raise ValidationError("Test cases are required")
            
            if len(test_cases) > 50:
                raise ValidationError("Maximum 50 test cases allowed")
            
            result = api_tester.batch_test(test_cases)
            
            response = SuccessResponse.create(
                data={"batch_result": result},
                message="Batch test completed"
            )
            return jsonify(response.dict())
            
        except ValidationError as e:
            raise
        except Exception as e:
            logger.error("Batch test error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Batch test failed"
            ).dict()), 500
    
    @app.route('/test/load', methods=['POST'])
    def load_test_endpoint():
        """负载测试API端点"""
        try:
            data = request.get_json()
            
            url = data.get('url')
            method = data.get('method', 'GET').upper()
            concurrent_users = min(data.get('concurrent_users', 10), 100)  # 限制最大并发数
            duration_seconds = min(data.get('duration_seconds', 30), 300)  # 限制最大测试时间
            request_data = data.get('data')
            headers = data.get('headers', {})
            
            if not url:
                raise ValidationError("URL is required")
            
            result = api_tester.load_test(
                url=url,
                method=method,
                concurrent_users=concurrent_users,
                duration_seconds=duration_seconds,
                data=request_data,
                headers=headers
            )
            
            response = SuccessResponse.create(
                data={"load_test_result": result},
                message="Load test completed"
            )
            return jsonify(response.dict())
            
        except ValidationError as e:
            raise
        except Exception as e:
            logger.error("Load test error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Load test failed"
            ).dict()), 500
    
    @app.route('/test/history', methods=['GET'])
    def get_test_history():
        """获取测试历史"""
        try:
            limit = min(int(request.args.get('limit', 100)), 1000)
            
            history = api_tester.get_test_history(limit)
            
            response = SuccessResponse.create(
                data={
                    "history": history,
                    "total_tests": len(history)
                },
                message="Test history retrieved"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Get history error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to retrieve test history"
            ).dict()), 500
    
    @app.route('/test/history', methods=['DELETE'])
    def clear_test_history():
        """清空测试历史"""
        try:
            api_tester.clear_test_history()
            
            response = SuccessResponse.create(
                message="Test history cleared"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Clear history error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to clear test history"
            ).dict()), 500
    
    # ========================================================================
    # 预设测试场景
    # ========================================================================
    
    @app.route('/test/scenarios/basic', methods=['POST'])
    def run_basic_scenario():
        """运行基础测试场景"""
        try:
            data = request.get_json()
            base_url = data.get('base_url', 'http://localhost:5000')
            
            # 基础测试用例
            test_cases = [
                {
                    "method": "GET",
                    "url": f"{base_url}/health",
                    "expected_status": 200
                },
                {
                    "method": "GET",
                    "url": f"{base_url}/info",
                    "expected_status": 200
                },
                {
                    "method": "GET",
                    "url": f"{base_url}/nonexistent",
                    "expected_status": 404
                }
            ]
            
            result = api_tester.batch_test(test_cases)
            
            response = SuccessResponse.create(
                data={"scenario_result": result},
                message="Basic scenario completed"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Basic scenario error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Basic scenario failed"
            ).dict()), 500
    
    @app.route('/test/scenarios/auth', methods=['POST'])
    def run_auth_scenario():
        """运行认证测试场景"""
        try:
            data = request.get_json()
            base_url = data.get('base_url', 'http://localhost:5000')
            
            # 认证测试用例
            test_cases = [
                {
                    "method": "POST",
                    "url": f"{base_url}/auth/register",
                    "data": {
                        "username": f"testuser_{generate_uuid()[:8]}",
                        "email": f"test_{generate_uuid()[:8]}@example.com",
                        "password": "testpassword123"
                    },
                    "expected_status": 201
                },
                {
                    "method": "POST",
                    "url": f"{base_url}/auth/login",
                    "data": {
                        "username": "nonexistent",
                        "password": "wrongpassword"
                    },
                    "expected_status": 401
                },
                {
                    "method": "GET",
                    "url": f"{base_url}/auth/me",
                    "expected_status": 401
                }
            ]
            
            result = api_tester.batch_test(test_cases)
            
            response = SuccessResponse.create(
                data={"scenario_result": result},
                message="Auth scenario completed"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Auth scenario error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Auth scenario failed"
            ).dict()), 500
    
    # ========================================================================
    # 性能监控
    # ========================================================================
    
    @app.route('/monitor/performance', methods=['GET'])
    def get_performance_stats():
        """获取性能统计"""
        try:
            history = api_tester.get_test_history()
            
            if not history:
                return jsonify(SuccessResponse.create(
                    data={"message": "No test data available"},
                    message="Performance stats retrieved"
                ).dict())
            
            # 计算统计数据
            successful_tests = [t for t in history if t.get('success', False)]
            failed_tests = [t for t in history if not t.get('success', False)]
            
            durations = [t['duration'] for t in history if 'duration' in t]
            
            stats = {
                "total_tests": len(history),
                "successful_tests": len(successful_tests),
                "failed_tests": len(failed_tests),
                "success_rate": len(successful_tests) / len(history) * 100 if history else 0,
                "average_response_time": statistics.mean(durations) if durations else 0,
                "min_response_time": min(durations) if durations else 0,
                "max_response_time": max(durations) if durations else 0,
                "median_response_time": statistics.median(durations) if durations else 0,
                "recent_tests": history[-10:] if len(history) > 10 else history
            }
            
            response = SuccessResponse.create(
                data={"performance_stats": stats},
                message="Performance stats retrieved"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Performance stats error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to retrieve performance stats"
            ).dict()), 500
    
    # ========================================================================
    # 应用信息
    # ========================================================================
    
    @app.route('/health', methods=['GET'])
    def health_check():
        """健康检查"""
        return jsonify({
            "status": "healthy",
            "timestamp": datetime.utcnow().isoformat(),
            "service": "API Testing Tool"
        })
    
    @app.route('/info', methods=['GET'])
    def app_info():
        """应用信息"""
        return jsonify({
            "name": "Flask API Testing Tool",
            "version": "1.0.0",
            "description": "API测试和性能监控工具",
            "features": [
                "单个API测试",
                "批量API测试",
                "负载测试",
                "性能监控",
                "测试历史记录",
                "预设测试场景"
            ],
            "endpoints": {
                "testing": [
                    "POST /test/single - 单个API测试",
                    "POST /test/batch - 批量API测试",
                    "POST /test/load - 负载测试",
                    "GET  /test/history - 获取测试历史",
                    "DELETE /test/history - 清空测试历史"
                ],
                "scenarios": [
                    "POST /test/scenarios/basic - 基础测试场景",
                    "POST /test/scenarios/auth - 认证测试场景"
                ],
                "monitoring": [
                    "GET /monitor/performance - 性能统计"
                ]
            },
            "usage_examples": {
                "single_test": {
                    "method": "POST",
                    "url": "/test/single",
                    "body": {
                        "method": "GET",
                        "url": "http://localhost:5000/health",
                        "expected_status": 200
                    }
                },
                "load_test": {
                    "method": "POST",
                    "url": "/test/load",
                    "body": {
                        "url": "http://localhost:5000/health",
                        "method": "GET",
                        "concurrent_users": 10,
                        "duration_seconds": 30
                    }
                }
            }
        })
    
    return app


if __name__ == '__main__':
    app = create_api_testing_app()
    
    print("=" * 60)
    print("Flask API Testing Tool")
    print("=" * 60)
    print("API测试功能:")
    print("  单个测试:")
    print("    POST /test/single - 测试单个API端点")
    print("  批量测试:")
    print("    POST /test/batch - 批量测试多个API端点")
    print("  负载测试:")
    print("    POST /test/load - 对API端点进行负载测试")
    print("  测试历史:")
    print("    GET  /test/history - 获取测试历史记录")
    print("    DELETE /test/history - 清空测试历史")
    print()
    print("  预设场景:")
    print("    POST /test/scenarios/basic - 基础功能测试")
    print("    POST /test/scenarios/auth - 认证功能测试")
    print()
    print("  性能监控:")
    print("    GET /monitor/performance - 获取性能统计数据")
    print()
    print("  特性:")
    print("    - 支持多种HTTP方法")
    print("    - 并发负载测试")
    print("    - 响应时间统计")
    print("    - 成功率分析")
    print("    - 测试历史记录")
    print("    - 预设测试场景")
    print("    - 性能监控")
    print("=" * 60)
    
    app.run(
        host='0.0.0.0',
        port=5008,
        debug=True
    )